<?php

Raise::load('core.RaiseStaticClass');
Raise::load('core.RaiseVariable');
Raise::load('core.RaiseCollection');

/**
 * RaiseVariable class
 * To deal with variables
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.Core
 * @since 1.2
 */
class RaiseVariable extends RaiseStaticClass {

    /**
     * String Data Type
     */
    const TYPESTRING = 'string';

    /**
     * Integer Data Type
     */
    const TYPEINTEGER = 'integer';

    /**
     * Boolean Data Type
     */
    const TYPEBOOLEAN = 'boolean';

    /**
     * Double/Float Data Type
     */
    const TYPEDOUBLE = 'double';

    /**
     * Array Data Type
     */
    const TYPEARRAY = 'array';

    /**
     * Object / Class instance Data Type
     */
    const TYPEOBJECT = 'object';

    /**
     * Resource Data Type
     */
    const TYPERESOURCE = 'resource';

    /**
     * NULL
     */
    const TYPENULL = 'null';

    /**
     * Unknown Data Type
     */
    const TYPEUNKNOWN = 'unknown';

    /**
     * Get the data type of a particular variable
     * @param mixed $a a variable to check against
     * @return string The data type. Check against constants in Variable class
     * @static
     */
    public static function getDataType($a){
        switch(true){
            case is_null($a):
                return self::TYPENULL;
                break;
            case is_string($a):
                return self::TYPESTRING;
                break;
            case is_int($a):
                return self::TYPEINTEGER;
                break;
            case is_double($a):
                return self::TYPEDOUBLE;
                break;
            case is_bool($a):
                return self::TYPEBOOLEAN;
                break;
            case is_array($a):
                return self::TYPEARRAY;
                break;
            case is_object($a):
                return self::TYPEOBJECT;
                break;
            case is_resource($a):
                return self::TYPERESOURCE;
                break;
        }
        return self::TYPEUNKNOWN;
    }

    /**
     * Get the resource type of a particular resource
     * @param resource $a The resource to get from
     * @return string
     * @link http://php.net/get-resource-type
     * @static
     */
    public static function getResourceType($a){
        return get_resource_type($a);
    }

    /**
     * Gets the class name of a particular object
     * @param object $a
     * @return string|boolean Name of the class on success, FALSE on failure
     * @static
     * @link http://php.net/get-class
     */
    public static function getClassName($a){
        if(self::getDataType($a) == self::TYPEOBJECT){
            return get_class($a);
        }
        return false;
    }

    /**
     * Checks if the object is of this class or has this class as one of its parents
     * @param object $a The object to check
     * @param string $t The particular class name
     * @return boolean
     * @static
     */
    public static function isA($a, $t){
        return $a instanceof $t;
    }

    /**
     * Checks if the object is not of this class or do not has this class as one of its parents
     * @param object $a The object to check
     * @param string $t The particular class name
     * @return boolean
     * @link http://php.net/is-a
     * @static
     */
    public static function isNotA($a, $t){
        return !is_a($a, $t);
    }

    /**
     * Checks whether $a is an instance of the class $c
     * @param object|mixed $a
     * @param string $c
     * @return boolean
     */
    public static function isInstanceOf($a, $c){
        return $a instanceof $c;
    }

    /**
     * Checks if an object/class has another class as its superclass
     * @param string|object $a A class name or object instance to check
     * @param string $b Name of the super class to check
     * @return boolean TRUE if the object $a is the subclass of $b
     */
    public static function isSubclass($a, $b){
        return is_subclass_of($a, $b);
    }

    /**
     * Set a particular type to a variable
     * @param mixed $a The variable to change its type
     * @param string $type The type to change to. Use constants from RaiseVariable class.
     * @return boolean
     * @static
     * @link http://php.net/settype
     */
    public static function setType(&$a,$type){
        return settype($a, $type);
    }

    /**
     * Check if a variable can be called as a function or method of an object
     * @param mixed $a The variable to check
     * @return boolean TRUE if the variable is callable, FALSE otherwise
     * @static
     */
    public static function isCallable($a){
        return (bool)is_callable($a);
    }

    /**
     * Check if a variable is either of type integer or double
     * @param mixed $a The variable to check
     * @return boolean TRUE if the variable is integer or double, FALSE otherwise.
     */
    public static function isNumeric($a){
        return is_numeric($a);
    }

    /**
     * Check whether a variable is of a certain type(s)
     * @param mixed $a The variable to check
     * @param string|RaiseCollection|array $types The type or collection of types to check
     * @return boolean
     */
    public static function isType($a, $types){
        if(is_string($types)){
            return (RaiseVariable::getDataType($a) == self::TYPEOBJECT && RaiseVariable::getClassName($a) == $types) || RaiseVariable::getDataType($a) == $types;
        }elseif(is_array($types)){
            $types = new RaiseCollection($types);
            return (RaiseVariable::getDataType($a) == self::TYPEOBJECT && $types->indexOf(RaiseVariable::getClassName($a)) !== null) || $types->indexOf(RaiseVariable::getDataType($a)) !== null;
        }
        return false;
    }

    /**
     * Get the exact data type information which expands into the class name
     * of the object and the resource type of the resource.
     * @param mixed $a The variable to fetch its data type information
     * @return string
     */
    public static function typeInfo($a){
        if(is_null($a)){
            return self::TYPENULL;
        }elseif(is_scalar($a) || is_array($a)){
            return self::getDataType($a);
        }elseif(is_resource($a)){
            return self::TYPERESOURCE . '/' . get_resource_type($a);
        }elseif(is_object($a)){
            return self::TYPEOBJECT . '/' . get_class($a);
        }
        return self::TYPEUNKNOWN;

    }

    /**
     * Flips the value of two variables around
     * @param mixed $a First variable
     * @param mixed $b Second variable
     * @static
     */
    public static function flip(&$a, &$b){
        $t = $b;
        $b = $a;
        $a = $t;
        unset($t);
    }

    /**
     * Dump information about a variable
     * @param mixed $v The variable to dump
     * @param boolean $t (optional) TRUE to return information as string, and FALSE to output directly. Defaults to TRUE.
     * @param boolean $preformat (optional) Whether or not to wrap the output with &lt;pre> tags. Defaults to TRUE
     * @return string
     * @static
     * @link http://php.net/var-dump
     * @link http://php.net/var-export
     */
    public static function dump($v, $t = true, $preformat = true){
        if($t){
            $ret = '';
            if($preformat){
                $ret .= '<pre>';
            }
            $ret .= var_export($v,true);
            if($preformat){
                $ret .= '</pre>';
            }
            return $ret;
        }else{
            if($preformat){
                echo '<pre>';
            }
            var_dump($v);
            if($preformat){
                echo '</pre>';
            }
        }
    }

}